package com.app.shop.config.filter;


import com.app.shop.util.UserEntity;
import com.app.shop.config.security.ValidCodeErrorException;
import com.app.shop.util.JwtTokenUtils;
import com.app.shop.util.LoginUtil;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 验证用户名密码正确后，生成一个token，并将token返回给客户端
 * 该类继承自UsernamePasswordAuthenticationFilter，重写了其中的2个方法
 * attemptAuthentication ：接收并解析用户凭证。
 * successfulAuthentication ：用户成功登录后，这个方法会被调用，我们在这个方法里生成token。
 * @author chenliwei on 2019/1/27
 */
public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter {

    private String usernameParam = "username";
    private String passwordParam = "password";
    private String validCodeParam = "validateCode";

    private AuthenticationManager authenticationManager;

    public JWTLoginFilter(AuthenticationManager authenticationManager){
        this.authenticationManager = authenticationManager;
    }

    /**
     *接收并解析用户凭证
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {

        //用户账号
        String username = request.getParameter(usernameParam);
        //用户密码
        String password = request.getParameter(passwordParam);
        //用户验证码
        //String validCode = request.getParameter(validCodeParam);
        String validCode="";
        valid(username,password,validCode, request.getSession());
        return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        username,password,new ArrayList()
                )
        );

    }

    /**
     * 用户成功登录后，这个方法会被调用，这个方法里生成token
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {

        String username = ((UserEntity)authResult.getPrincipal()).getUsername();
        String name = ((UserEntity)authResult.getPrincipal()).getName();
        Integer userId = ((UserEntity)authResult.getPrincipal()).getUserId();
        Boolean isRememberMe = ((UserEntity)authResult.getPrincipal()).getRememberMe();
        Map<String, Object> claims =new HashMap<String, Object>();
        claims.put("username",username);
        claims.put("userId",userId);
        claims.put("isRememberMe",isRememberMe==null||!isRememberMe?false:true);
        String token = JwtTokenUtils.createToken(claims);
        System.out.println("【登录成功，token->】"+JwtTokenUtils.TOKEN_PREFIX+token);
        System.out.println("【登录成功，IP->】"+getIpAddress(request));
        response.addHeader(JwtTokenUtils.TOKEN_HEADER,JwtTokenUtils.TOKEN_PREFIX+token);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        //用户和token进行绑定
        LoginUtil.putUserToken(username,token);
        LoginUtil.removeLoginCnt(username);
        response.getWriter().println("{\"code\":200,\"message\":\"登录成功！\",\"data\":{\"token\":\"" +
                JwtTokenUtils.TOKEN_PREFIX + token + "\",\"username\":\"" + username + "\",\"name\":\""+name+"\",\"userId\":\""+userId+"\"}}");
        response.getWriter().flush();
    }

    /**
     * 这是验证失败时候调用的方法
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println("{\"code\":-1,\"message\":\"用户名或密码不正确！！\",\"data\":\"\"}");
        response.getWriter().flush();
    }

    /**
     * 这里从token中获取用户信息并新建一个token
     * @param tokenHeader
     * @return
     */
//    private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) {
//        String token = tokenHeader.replace(JwtTokenUtils.TOKEN_PREFIX, "");
//        String username = JwtTokenUtils.getUsername(token);
//        String role = JwtTokenUtils.getUserRole(token);
//        if (username != null){
//            return new UsernamePasswordAuthenticationToken(username, null,
//                    Collections.singleton(new SimpleGrantedAuthority(role))
//            );
//        }
//        return null;
//    }

    /**
     * 校验登录参数
     * @param username
     * @param password
     * @param validCode
     * @param session
     */
    public void valid(String username,String password,String validCode, HttpSession session) {

        if (username == null|"".equals(username)) {
            throw new ValidCodeErrorException("账号不允许为空!");
        }
        if (password == null|"".equals(password)) {
            throw new ValidCodeErrorException("密码不允许为空!");
        }
//        if (validCode == null|"".equals(validCode)) {
//            throw new ValidCodeErrorException("验证码不允许为空!");
//        }
//        if (!ValidateCodeHandle.matchCode(session.getId(), validCode)) {
//            throw new ValidCodeErrorException("验证码输入错误!");
//        }
    }

    /**
     * 获取登录用户IP字符串
     * @param request
     * @return 返回登录用户IP字符串
     * @author chenliwei
     */
    public String getIpAddress(HttpServletRequest request){

        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}
